﻿using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using System.Net;
using System.Text.RegularExpressions;
using System.Text;
using HtmlAgilityPack;
using AutoMapper;
using Hsp.WebNovels.Model;
using Hsp.WebNovels.Model.Models;

namespace Hsp.WebNovels.Web.Utilities
{
    public class BaseController : Controller
    {
        #region 构造函数及方法注入

        private readonly IMapper _mapper;
        private readonly ILogger<BaseController> _logger;
        private readonly NovelsContext _context;

        /// <summary>
        /// {areaName}区域基类控制器构造函数
        /// </summary>
        public BaseController(ILogger<BaseController> logger, NovelsContext context, IMapper mapper)
        {
            this._mapper = mapper;
            this._logger = logger;
            this._context = context;
        }

        #endregion

        public static string? Db_ConnectionString { get; set; }

        public static SqlSugarClient Db
        {
            get => new(new ConnectionConfig()
            {
                ConfigId = "0",
                DbType = DbType.SqlServer,
                ConnectionString = Db_ConnectionString,
                IsAutoCloseConnection = true
            });
        }

        /// <summary>
        /// 获取小说内容（异步）
        /// </summary>
        /// <param name="db"></param>
        /// <param name="encoding"></param>
        /// <param name="webSite"></param>
        /// <param name="xpathContent"></param>
        /// <param name="xpathNextPage"></param>
        /// <param name="chapter"></param>
        /// <param name="isGetText">正文类型：true-文本；false-HTML；</param>
        /// <returns></returns>
        internal static async Task GetNovelContentAsync(SqlSugarClient db, string encoding, string webSite, string xpathContent, string? xpathNextPage, Chapter chapter, bool isGetText)
        {
            if (string.IsNullOrEmpty(chapter.ChapterUrl))
            {
                return;
            }
            string? content = null;
            HtmlDocument? htmlContent = await HtmlDocAsync(chapter.ChapterUrl, encoding);
            if (htmlContent == null) return;
            if (isGetText)
            {
                var contentNode = htmlContent?.DocumentNode.SelectSingleNode(xpathContent);
                content = contentNode?.InnerText;
                // content = isGetText ? contentNode?.InnerText : contentNode?.InnerHtml;
            }
            else
            {
                var contentNodes = htmlContent?.DocumentNode.SelectNodes(xpathContent);
                if (contentNodes == null)
                {
                    return;
                }
                else
                {
                    foreach (var node in contentNodes)
                    {
                        content += node.InnerText + Environment.NewLine;
                    }
                }
            }

            if (content == null)
            {
                return;
            }
            content = ContentCleaning(content);

            if (!string.IsNullOrEmpty(xpathNextPage))
            {
                var nextUrl = GetNextUrl(htmlContent, xpathNextPage, webSite);

                chapter.NextUrl = nextUrl;

                // 这里要检查下一页的地址是否在章节地址数据里面，如果在，表明是跳到了下一章的地址，不再获取。

                if (!string.IsNullOrEmpty(nextUrl) && !(await CheckNextUrlAsync(db, nextUrl)))
                {
                    var nextContent = await GetNextContentsAsync(db, nextUrl, encoding, xpathContent, xpathNextPage, webSite, isGetText);
                    content += nextContent;
                }
            }

            chapter.WordCount = content.Length;
            chapter.ValidChapter = content.Length > 500 ? 1 : 0;

            chapter.UpdateTime = DateTime.Now;

            await db.Updateable(chapter).ExecuteCommandAsync();

            #region 小说内容保存

            Content chapterContent = await db.Queryable<Content>()
                .Where(c => c.ChapterId == chapter.Id).FirstAsync();

            if (chapterContent == null)
            {
                chapterContent = new();
                chapterContent.ChapterId = chapter.Id;
                chapterContent.NovelId = chapter.NovelId;
                chapterContent.Contents = content;

                await db.Insertable(chapterContent).ExecuteCommandAsync();
            }
            else
            {
                chapterContent.Contents = content;
                await db.Updateable(chapterContent).ExecuteCommandAsync();
            }

            #endregion

            await Console.Out.WriteLineAsync($"{Environment.CurrentManagedThreadId:00}-{chapter.ChapterTitle}");
        }

        /// <summary>
        /// 获取页面HTML内容（异步）
        /// </summary>
        /// <param name="url"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        internal static async Task<HtmlDocument?> HtmlDocAsync(string url, string encoding)
        {
            //using HttpClient client = new();
            //Uri? requestUri = new(url);
            //以byte[]获取html
            byte[]? bytes = await HttpHelper.HttpGetAsync(url);
            if (bytes == null) return null;
            //client.GetByteArrayAsync(requestUri).Result;
            //将byte[]重新编码成GB2312;
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            string html = Encoding.GetEncoding(encoding).GetString(bytes);
            //解析html,并输入
            HtmlDocument htmlDoc = new();
            htmlDoc.LoadHtml(html);

            return htmlDoc;
        }

        /// <summary>
        /// 递归获取下一页内容（异步）
        /// </summary>
        /// <param name="nextUrl"></param>
        /// <param name="encoding"></param>
        /// <param name="xpath"></param>
        /// <param name="nextPath"></param>
        /// <param name="webSite"></param>
        /// <param name="isGetText"></param>
        /// <returns></returns>
        // 递归获取下一页内容
        internal static async Task<string> GetNextContentsAsync(SqlSugarClient db, string nextUrl, string encoding, string xpath, string nextPath, string webSite, bool isGetText)
        {
            //HtmlDocument? nextHtmlDoc = await HtmlDocAsync(nextUrl, encoding);
            //if (nextHtmlDoc == null) return "";
            //var nextContentNode = nextHtmlDoc?.DocumentNode.SelectSingleNode(xpath);
            //var nextContent = isGetText ? nextContentNode?.InnerText : nextContentNode?.InnerHtml;

            string? nextContent = null;
            HtmlDocument? nextHtmlDoc = await HtmlDocAsync(nextUrl, encoding);
            if (nextHtmlDoc == null) return "";
            if (isGetText)
            {
                var contentNode = nextHtmlDoc?.DocumentNode.SelectSingleNode(xpath);
                nextContent = contentNode?.InnerText;
                // content = isGetText ? contentNode?.InnerText : contentNode?.InnerHtml;
            }
            else
            {
                var contentNodes = nextHtmlDoc?.DocumentNode.SelectNodes(xpath);
                if (contentNodes == null)
                {
                    return "";
                }
                else
                {
                    foreach (var node in contentNodes)
                    {
                        nextContent += node.InnerText + Environment.NewLine;
                    }
                }
            }

            var content = ContentCleaning(nextContent);

            nextUrl = GetNextUrl(nextHtmlDoc, nextPath, webSite);

            // 这里要检查下一页的地址是否在章节地址数据里面，如果在，表名是跳到了下一章的地址，不再获取。

            if (!string.IsNullOrEmpty(nextUrl) && !(await CheckNextUrlAsync(db, nextUrl)))
            {
                content += await GetNextContentsAsync(db, nextUrl, encoding, xpath, nextPath, webSite, isGetText);
            }

            return content;
        }

        /// <summary>
        /// 检查下一页内容地址是否存在于章节地址中
        /// </summary>
        /// <param name="db"></param>
        /// <param name="nextUrl">下一页内容地址</param>
        /// <returns></returns>
        internal static async Task<bool> CheckNextUrlAsync(SqlSugarClient db, string nextUrl)
        {
            return await db.Queryable<Chapter>()
                        .Where(c => c.ChapterUrl == nextUrl).AnyAsync();
        }


        internal static HtmlDocument HtmlDoc(string url, string encoding)
        {
            using HttpClient client = new();
            Uri? requestUri = new(url);
            //以byte[]获取html
            byte[] bytes = client.GetByteArrayAsync(requestUri).Result;
            //将byte[]重新编码成GB2312;
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            string html = Encoding.GetEncoding(encoding).GetString(bytes);
            //解析html,并输入
            HtmlDocument htmlDoc = new();
            htmlDoc.LoadHtml(html);

            return htmlDoc;
        }

        internal static ChapterTitle TitleCleaning(string title)
        {
            ChapterTitle chapterTitle = new();

            var chapterTemplate = "第$2章";

            var chapterIdx = 0;
            var titleContent = title;
            string expTitle = "([第]{0,1})([○零一二三四五六七八九十百千\\d]{1,})([节章]{0,1}[：:。, ]{0,2})([\\s\\S]*?)";
            var titleChapter = TextHelper.ContentExtract(title, expTitle); // 标题章节数字

            if (!string.IsNullOrEmpty(titleChapter))
            {
                titleChapter = titleChapter.Replace(Environment.NewLine, "&");
                titleChapter = titleChapter.Split('&')[0];

                titleContent = title.Replace(titleChapter, ""); // 标题名称（除去章节数字）
                titleChapter = titleChapter.Replace("。", "").Replace("：", "");

                var expChineseDig = "([○零一二三四五六七八九十百千]{1,})";
                var strChineseChapter = TextHelper.ContentExtract(titleChapter, expChineseDig); // 章节中文数字 
                strChineseChapter = strChineseChapter.Replace(Environment.NewLine, "&");
                strChineseChapter = strChineseChapter.Split('&')[0];

                if (strChineseChapter.Length == 0)
                {
                    // 阿拉伯数字
                    titleChapter = TextHelper.ContentExtract(titleChapter, "([\\d]{1,})");
                    titleChapter = titleChapter.Replace(Environment.NewLine, "");
                    int.TryParse(titleChapter, out chapterIdx);
                }
                else
                {
                    if (TextHelper.ContentExtract(strChineseChapter, "([十百千]{1,})").Length > 0)
                    {
                        chapterIdx = int.Parse(TextHelper.DecodeMoneyCn(strChineseChapter).ToString());
                    }
                    else
                    {
                        chapterIdx = int.Parse(TextHelper.DecodeSimpleCn(strChineseChapter));
                    }
                }

                if (!string.IsNullOrEmpty(titleContent))
                {
                    titleContent = titleContent.Trim().TrimEnd('.');
                    titleContent = titleContent.TrimStart(','); // 标题前面的半角逗号清理

                    #region 处理标题中“几更”信息

                    if (!string.IsNullOrEmpty(titleContent) && titleContent.Contains('更'))
                    {
                        var exp = "([(（]{1})([\\s\\S]*?)([）)]{1})";
                        var result = TextHelper.ContentExtract(titleContent, exp);

                        if (!string.IsNullOrEmpty(result) && result.Contains('更'))
                        {
                            result = result.TrimEnd('\n').TrimEnd('\r');
                            result = result.Replace("\n", "").Replace("\r", "");
                            titleContent = titleContent.Replace(result, "");
                        }
                    }

                    #endregion

                    titleContent = titleContent.Trim();
                    titleContent = titleContent.Replace("&nbsp;", "");

                    titleContent = titleContent.Replace("（新书求支持）", "");
                    titleContent = titleContent.Replace("（求收藏、求鲜花）", "");
                    titleContent = titleContent.Replace("（求收藏）", "");
                    titleContent = titleContent.Replace("（求订阅）", "");
                    titleContent = titleContent.Replace("（改）", "");

                    //titleContent = titleContent.Replace("（第一更！）", "");
                    //titleContent = titleContent.Replace("（第二更！）", "");
                    //titleContent = titleContent.Replace("（第三更！）", "");
                    //titleContent = titleContent.Replace("（第四更！）", "");
                    //titleContent = titleContent.Replace("（第五更！）", "");
                    //titleContent = titleContent.Replace("（第六更！）", "");
                    //titleContent = titleContent.Replace("（第七更！）", "");
                    //titleContent = titleContent.Replace("（第八更！）", "");
                    //titleContent = titleContent.Replace("（第九更！）", "");

                    //titleContent = titleContent.Replace("（第十更！）", "");
                    //titleContent = titleContent.Replace("（第十一更！）", "");
                    //titleContent = titleContent.Replace("（第十二更！）", "");
                    //titleContent = titleContent.Replace("（第十三更！）", "");
                    //titleContent = titleContent.Replace("（第十四更！）", "");
                    //titleContent = titleContent.Replace("（第十五更！）", "");

                    titleContent = titleContent.Replace("（第一更）", "");
                    titleContent = titleContent.Replace("（第二更）", "");
                    titleContent = titleContent.Replace("（第三更）", "");
                    titleContent = titleContent.Replace("（第二）", "");

                    titleContent = titleContent.Replace("【求鲜花】", "");
                    titleContent = titleContent.Replace("【求首订】", "");
                    titleContent = titleContent.Replace("【鲜花】", "");

                    titleContent = titleContent.Replace("求订阅", "");
                    titleContent = titleContent.Replace("求全定", "");
                    titleContent = titleContent.Replace("求收藏", "");
                    titleContent = titleContent.Replace("求首订", "");

                    titleContent = titleContent.Replace("重复已修改", "");
                    titleContent = titleContent.Replace("补上昨天的", "");

                    titleContent = titleContent.Replace("【】", "").Replace("（）", "").Replace("()", "");

                    //（改）
                }

                // 第$2章
                if (chapterIdx > 0)
                {
                    titleChapter = chapterTemplate.Replace("$2", chapterIdx.ToString());
                }

                if (string.IsNullOrEmpty(titleChapter))
                {
                    titleChapter = "第$2章".Replace("$2", chapterIdx.ToString());
                }

            }


            chapterTitle.Idx = chapterIdx;
            chapterTitle.Name = titleChapter;
            chapterTitle.HeadWord = titleContent;
            chapterTitle.Title = titleChapter + " " + titleContent;

            return chapterTitle;
        }

        internal static string ContentCleaning(string content)
        {
            if (string.IsNullOrEmpty(content))
            {
                return string.Empty;
            }
            //content = content.Trim();
            content = content.TrimStart('\r').TrimStart('\n');
            content = content.TrimEnd('\n').TrimStart('\r');

            content = content.Replace("<br><br>", "<br>").Replace("<br>", Environment.NewLine);

            content = content.Replace("&nbsp;", "");
            content = content.Replace("&#12290;", "。");
            content = content.Replace("&#24819;", "想");

            content = content.Replace("\r\n”", "”");
            content = content.Replace("\r\n、", "、");

            content = ContentHelper.RegexReplace("<p[^>]*>([\\s\\S]*?)</p>", content, "");

            //content = content.Replace("(第1/4页)本章未完，请点击&#8595;&#8595;&#8595;继续阅读", "");
            //content = content.Replace("(第2/4页)本章未完，请点击&#8595;&#8595;&#8595;继续阅读", "");
            //content = content.Replace("(第3/4页)本章未完，请点击&#8595;&#8595;&#8595;继续阅读", "");
            //content = content.Replace("(第4/4页)本章未完，请点击&#8595;&#8595;&#8595;继续阅读", "");

            content = content.Replace("......", "");
            content = content.Replace("网页版章节内容慢，请下载好阅小说app阅读最新内容", "");
            content = content.Replace("请退出转码页面，请下载好阅小说app 阅读最新章节。", "");

            return content;
        }

        /// <summary>
        /// 获取下一页内容地址
        /// </summary>
        /// <param name="htmlDoc"></param>
        /// <param name="nextPath"></param>
        /// <param name="webSite"></param>
        /// <returns></returns>
        internal static string GetNextUrl(HtmlDocument htmlDoc, string nextPath, string webSite)
        {
            var nextNode = htmlDoc.DocumentNode.SelectSingleNode(nextPath);
            if (nextNode == null) return "";
            var href = nextNode.Attributes["href"];
            if (href == null) return "";
            var nextUrl = href.Value.Trim();
            if (nextUrl.Contains("javascript") || string.IsNullOrEmpty(nextUrl)) return "";
            if (nextUrl.Contains("http")) return nextUrl;

            if (!webSite.EndsWith("/")) webSite += "/";
            if (nextUrl.StartsWith("/")) nextUrl = nextUrl.TrimStart('/');

            return $"{webSite}{nextUrl}";
        }

        // 递归获取下一页内容
        internal static string GetNextContents(string nextUrl, string encoding, string xpath, string nextPath, string webSite)
        {
            HtmlDocument nextHtmlDoc = HtmlDoc(nextUrl, encoding);
            var nextContentNode = nextHtmlDoc.DocumentNode.SelectSingleNode(xpath);
            if (nextContentNode == null) return "";
            var nextContent = nextContentNode.InnerHtml;
            var content = ContentCleaning(nextContent);

            nextUrl = GetNextUrl(nextHtmlDoc, nextPath, webSite);

            if (!string.IsNullOrEmpty(nextUrl))
            {
                content += GetNextContents(nextUrl, encoding, xpath, nextPath, webSite);
            }

            return content;
        }

        //自动获取网页编码
        internal static Encoding GetWebEncoding(string serverUrl)
        {
            WebRequest request = WebRequest.Create(serverUrl);
            WebResponse response = request.GetResponse();
            Stream sr = response.GetResponseStream();
            byte[] buffer = new byte[1200];
            sr.Read(buffer, 0, buffer.Length);
            string head = Encoding.Default.GetString(buffer);
            string regPatt = @"charset\s*=\s*(?<encode>\w+)";
            Regex regEncode = new Regex(regPatt, RegexOptions.IgnoreCase
                | RegexOptions.Compiled);
            string encodname = regEncode.Match(head).Result("${encode}");

            return Encoding.GetEncoding(encodname);
        }
    }
}
